using System;
using System.Linq;
using Upreader.Application;
using Upreader.Engine;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using Upreader.Presentation.Client.ViewModel.Common;
using Microsoft.Practices.Prism.Commands;
using System.ComponentModel.Composition;

namespace Upreader.Presentation.Client.ViewModel
{
    /// <summary>
    /// This class contains properties that the main View can data bind to.
    /// </summary>
    [Export]
    public class MainViewModel : ViewModelBase<MainViewModel>
    {
        #region Fields

        private readonly DownloadEngine _engine;

        private readonly ObservableCollection<ServerViewModel> _serverProcessorViewModels = new ObservableCollection<ServerViewModel>();

        TaskWithCancellationTokenSource _downloadTaskTracker;
        //TaskWithCancellationTokenSource _repairTaskTracker;
        //TaskWithCancellationTokenSource _unpackTaskTracker;

        #endregion // Fields

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel()
        {
            // setup commands
            StartDownloadCommand = new DelegateCommand(StartDownload, CanStartDownload);
        }

        #endregion // Constructor

        #region Commands

        public DelegateCommand StartDownloadCommand { get; set; }
        public DelegateCommand StopDownloadCommand { get; set; }

        #endregion // Commands
         
        #region Properties

        public ReadOnlyObservableCollection<ServerViewModel> ServerProcessorObservableCollection
        {
            get { return new ReadOnlyObservableCollection<ServerViewModel>(_serverProcessorViewModels); }
        }

        public Exception DownloadException
        {
            get
            {
                if (_downloadTaskTracker == null)
                    return null;

                return _downloadTaskTracker.Task.Exception;
            }
        }

        #endregion // Properties

        #region Methods

        public override void OnImportsSatisfied()
        {
            base.OnImportsSatisfied();

            DownloadEngine.ServerProcessorAdded += new EventHandler<ServerProcessorEventArgs>(OnEngineServerProcessorAdded);
            DownloadEngine.ServerProcessorRemoved += new EventHandler<ServerProcessorEventArgs>(OnEngineServerProcessorRemoved);
        }

        public void StartDownload()
        {
            if (!CanStartDownload())
                throw new InvalidOperationException("Can't start downloading when already running");

            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
            CancellationToken cancellationToken = cancellationTokenSource.Token;

            Task downloadTask = _engine.StartDownloadTask(cancellationToken).ContinueWith(antecendent => 
            {
                if (antecendent.IsFaulted)
                {
                    RaisePropertyChanged(x => x.DownloadException);
                }

                StartDownloadCommand.RaiseCanExecuteChanged();
                StopDownloadCommand.RaiseCanExecuteChanged();

            }, TaskScheduler.FromCurrentSynchronizationContext());

            _downloadTaskTracker = new TaskWithCancellationTokenSource(downloadTask, cancellationTokenSource);
        }

        public void StopDownload()
        {
            if (!CanStopDownload())
                throw new InvalidOperationException("Can't stop downloading when not running");

            _downloadTaskTracker.CancellationTokenSource.Cancel(); // property notification is handeled in the ContinueWith hook registered in StartDownload
        }

        public bool CanStartDownload()
        {
            if (_downloadTaskTracker == null)
                return true;
            else
            {
                switch (_downloadTaskTracker.Task.Status)
                {
                    case TaskStatus.Canceled:
                    case TaskStatus.Faulted:
                    case TaskStatus.RanToCompletion:
                        return true;
                    default:
                        return false;
                }
            }
        }

        public bool CanStopDownload()
        {
            return !CanStartDownload();
        }

        #endregion // Methods

        #region EventHandlers

        private void OnEngineServerProcessorAdded(object sender, ServerProcessorEventArgs e)
        {
            ServerViewModel viewModel = ServiceLocator.GetInstance<ServerViewModel>();
            _serverProcessorViewModels.Add(viewModel);
        }

        private void OnEngineServerProcessorRemoved(object sender, ServerProcessorEventArgs e)
        {
            ServerViewModel viewModel = _serverProcessorViewModels.First(x => x.ServerProcessor == e.ServerProcessor);
            _serverProcessorViewModels.Remove(viewModel);
        }

        #endregion // EventHandlers
    }
}